// **************************************************************
// COPYRIGHT(c)2010, xidian University
// All rights reserved.
//
// IP LIB INDEX  :  HiNOC
// IP Name       :  HiNOC
// File name     :  insert_read_bus.v
// Module name   :  INSERT_READ_BUS
// Full name     :  INSERT READ DATA FROM CPU BUS
//
// Author        :  Pan Weitao
// Email         :  panweitao@163.com
// Data          :  2010?10?28?9:54:26
// Version       :  V 1.0
//
// Abstract      :
// Called by     :  
//
// Modification history
// Yin Lingzhi,2012/12/18
// ------------------------------------------------------------------------------------------------------
// //
// 21/6/2 dpram_status寄存器从0改为保持
// 21/6/7 将ram读数据打一拍后，去掉一个WAIT状态机
// 
// *********************************************************************
`timescale 1ns/100ps
`define E_th 8'd129  //该des_id代表改不需要入队,插入H口
// *****************************
//  DEFINE MODULE PORT  //
// ******************************
module insert_new(
                       //input
                       clk                      ,
                       rst_n                      ,
					   
					   //connect cpu interfase
                       insert_end               ,
                       frame_pri                ,
                       frame_len                ,
                       des_id                   ,
                       dpram_status             ,
                       //dpram_stat_WE            ,
                       //insert_ins_WE            ,
					   
                       //插入数据
					   dpram0_data              ,
                       dpram0_addr              ,
					   
					   //E口分组处理
                       frame_pri_o_e            ,
                       des_id_o_e               ,
                       empty_e                  ,
                       insert_data_rdy_e        ,
                       insert_data_o_e          ,
                       insert_data_val_o_e      ,
                       insert_data_sop_e        ,
                       insert_data_eop_e        ,
                       insert_data_mode_e       ,
                       insert_data_dsav_e       ,
					   
					   //H口分组处理
                       frame_pri_o_h            ,
                       des_id_o_h                ,
                       empty_h                   ,
                       insert_data_rdy_h         ,
                       insert_data_o_h           ,
                       insert_data_val_o_h       ,        
                       insert_data_sop_h         ,
                       insert_data_eop_h         ,
                       insert_data_mode_h        ,
                       insert_data_dsav_h        
                      );

// ******************************
// DEFINE PARAMETER
// ******************************
parameter [5:0]   IDLE    =   6'b000000   ;
parameter [5:0]   READY   =   6'b000001   ;
parameter [5:0]   WAIT    =   6'b000010   ;
parameter [5:0]   START   =   6'b000100   ;
parameter [5:0]   TRANS   =   6'b001000   ;
parameter [5:0]   FINISH  =   6'b010000   ;
 
// ******************************
// DEFINE INPUT
// ******************************                              
input          clk                    ;
input          rst_n                    ;                        
input          insert_end             ;//CPU将数据插入到RAM完成后给出插入结束信号
input  [2:0]   frame_pri              ;//CPU插入的以太网帧的优先级
input  [10:0]  frame_len              ;//CPU插入的以太网帧的帧长
input  [7:0]   des_id                 ;//CPU插入的以太网帧的目的结点
input  [255:0] dpram0_data            ;//存放插入数据RAM的输出数据   
input          insert_data_rdy_e      ;//来自分组处理E口的准备好信号，准备接收插入的以太网帧
input          insert_data_rdy_h      ;//来自分组处理H口的准备好信号，准备接收插入的以太网帧
// ******************************
// DEFINE OUTPUT  //
// ******************************      
output         dpram_status           ;//CPU接口模块中的dpram状态寄存器，最低一位表示RAM中是否有数据。1表示有数据，0表示无数据。插入完成时置位1，发送完成后置位0。
//output         dpram_stat_WE          ;//dpram状态寄存器的写使能
//output         insert_ins_WE          ;//插入状态寄存器，当CPU插入完成后置位1，发送完成后清除有效位。
output [2:0]   frame_pri_o_e          ;//向分组处理E口模块输出插入帧的优先级
output [7:0]   des_id_o_e             ;//向分组处理E口模块输出插入帧的目的节点用于入队。
output [2:0]   frame_pri_o_h          ;//向分组处理H口模块输出插入帧的优先级
output [7:0]   des_id_o_h             ;//向分组处理H口模块输出插入帧的目的节点用于入队。


output         empty_e                ;//告诉EMAC分组处理E口是否有插入数据
output         empty_h                ;//告诉EMAC分组处理H口是否有插入数据
output [5:0]   dpram0_addr            ;//读RAM的地址
//与EMAC分组处理模块的接口，类似于MI I接口
//E口
(*mark_debug = "true"*) output [255:0] insert_data_o_e          ;
(*mark_debug = "true"*) output         insert_data_val_o_e      ;
(*mark_debug = "true"*) output         insert_data_sop_e        ;
(*mark_debug = "true"*) output         insert_data_eop_e        ;
(*mark_debug = "true"*) output [4:0]   insert_data_mode_e       ;
(*mark_debug = "true"*) output         insert_data_dsav_e       ;
//H???
output [255:0] insert_data_o_h          ;
output         insert_data_val_o_h      ;
output         insert_data_sop_h        ;
output         insert_data_eop_h        ;
output [4:0]   insert_data_mode_h       ;
output         insert_data_dsav_h       ;
// ******************************
// OUTPUT ATRRIBUTE  //
// ******************************                                   
//REGS
reg    [5:0]   dpram0_addr              ;
reg            dpram_status             ;
//reg            insert_ins_WE            ;

//e
reg    [2:0]   frame_pri_o_e            ;
reg    [7:0]   des_id_o_e               ;
reg            empty_e                  ;

//h
reg    [2:0]   frame_pri_o_h            ;
reg    [7:0]   des_id_o_h               ;
reg            empty_h                  ;

//
reg    [255:0] insert_data_o            ;
reg            insert_data_val_o        ;
reg            insert_data_sop          ;
reg            insert_data_eop          ;
reg    [4:0]   insert_data_mode         ;
reg            insert_data_dsav         ;


//WIRES

// ******************************
// INTERNAL ATRRIBUTE  //
// ******************************                                   
//REGS
reg    [5:0]   current_state          ;
reg    [5:0]   next_state             ;
reg    [6:0]   wtimes                 ;
reg            insert_end_ff1         ;
reg            insert_end_ff2         ;
reg            insert_end_pos_ff1     ;
reg            trans_end              ;//发送完成
reg            trans_end_ff1          ;
reg            insert_data_rdy_e_ff1  ;
reg            insert_data_rdy_h_ff1  ;
//WIRES
wire           insert_end_pos         ;
wire           insert_data_rdy_pos    ;
wire           trans_end_neg          ;

// ******************************
//MAIN CODE  //
// ******************************
assign  trans_end_neg = (trans_end == 1'b0) && (trans_end_ff1 == 1'b1);
//assign  dpram_stat_WE = insert_end_pos_ff1 | trans_end_neg; //插入完成及发送完成时更新dpram状态寄存器
assign  insert_end_pos = (insert_end_ff2 == 1'b0) && (insert_end_ff1 == 1'b1);
assign  insert_data_rdy_pos = ((insert_data_rdy_e == 1'b1) && (insert_data_rdy_e_ff1 == 1'b0)) || ((insert_data_rdy_h == 1'b1) && (insert_data_rdy_h_ff1 == 1'b0));

assign insert_data_o_h     = ( des_id == `E_th )? insert_data_o     : 256'd0 ;
assign insert_data_val_o_h = ( des_id == `E_th )? insert_data_val_o : 1'b0   ;
assign insert_data_sop_h   = ( des_id == `E_th )? insert_data_sop   : 1'b0   ;
assign insert_data_eop_h   = ( des_id == `E_th )? insert_data_eop   : 1'b0   ;
assign insert_data_mode_h  = ( des_id == `E_th )? insert_data_mode  : 5'b0   ;
assign insert_data_dsav_h  = ( des_id == `E_th )? insert_data_dsav  : 1'b0   ;

assign insert_data_o_e     = ( des_id == `E_th )? 256'd0 : insert_data_o     ;
assign insert_data_val_o_e = ( des_id == `E_th )? 1'b0   : insert_data_val_o ;
assign insert_data_sop_e   = ( des_id == `E_th )? 1'b0   : insert_data_sop   ;
assign insert_data_eop_e   = ( des_id == `E_th )? 1'b0   : insert_data_eop   ;
assign insert_data_mode_e  = ( des_id == `E_th )? 5'b0   : insert_data_mode  ;
assign insert_data_dsav_e  = ( des_id == `E_th )? 1'b0   : insert_data_dsav  ;



always @ (posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        insert_end_ff1          <= 1'b0;
        insert_end_ff2          <= 1'b0;
        insert_end_pos_ff1      <= 1'b0;
    end
    else
    begin
        insert_end_ff1          <= insert_end;
        insert_end_ff2          <= insert_end_ff1;
        insert_end_pos_ff1      <= insert_end_pos;
    end
end


always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
    begin
        frame_pri_o_e         <= 3'b0;
        des_id_o_e            <= 8'b0;
    end
    else if (insert_end_pos == 1'b1 && des_id != `E_th )
    begin
        frame_pri_o_e         <= frame_pri;
        des_id_o_e            <= des_id;
    end
end

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
    begin
        frame_pri_o_h         <= 3'b0;
        des_id_o_h            <= 8'b0;
    end
    else if (insert_end_pos == 1'b1 && des_id == `E_th )  //des_id为不需要入队的插入H口
    begin
        frame_pri_o_h         <= frame_pri;
        des_id_o_h            <= des_id;
    end
end

//可能无用
/*always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_ins_WE       <= 1'b0;
    else if (trans_end_neg == 1'b1)
        insert_ins_WE       <= 1'b1;
    else
        insert_ins_WE       <= 1'b0;
end*/

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        dpram_status        <= 1'b0;
    else if (insert_end_pos == 1'b1)
        dpram_status        <= 1'b1;
    else if (trans_end == 1'b1)
        dpram_status        <= 1'b0;
    else
        dpram_status        <= dpram_status;//6.2 1'b0 -> dpram_status
end

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        empty_e             <= 1'b1;
    else if (insert_end_pos == 1'b1 && des_id != `E_th)
        empty_e             <= 1'b0;
    // else if (trans_end_neg == 1'b1) 
    else if (trans_end == 1'b1) 
        empty_e             <= 1'b1;
    else
        empty_e             <= empty_e ;
end 

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        empty_h              <= 1'b1;
    else if (insert_end_pos == 1'b1 && des_id == `E_th)
        empty_h              <= 1'b0;
    // else if (trans_end_neg == 1'b1) 
    else if (trans_end == 1'b1) 
        empty_h              <= 1'b1;
    else
        empty_h              <= empty_h;
end 

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_data_rdy_e_ff1     <= 1'b0;
    else
        insert_data_rdy_e_ff1     <= insert_data_rdy_e;
end

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_data_rdy_h_ff1     <= 1'b0;
    else
        insert_data_rdy_h_ff1     <= insert_data_rdy_h;
end


//FSM seq part
always @ (posedge clk or negedge rst_n)
begin
    if(~rst_n)
        current_state <= IDLE;
    else
        current_state <= next_state;
end
//FSM comb part
always @ ( * )
begin
    case(current_state)
        IDLE:
            begin
                if(insert_data_rdy_pos == 1'b1)
                     next_state = READY;
                else
                     next_state = IDLE;
            end      
        READY:
            next_state = WAIT; 
        WAIT:
            next_state = START;
        START://sop
            begin
                if(wtimes==7'd0)
                     next_state = FINISH;
                else
                     next_state = TRANS; 
            end
        TRANS:  
            begin
                if(wtimes==7'd0)
                     next_state = FINISH;
                else
                     next_state = TRANS; 
            end             
        FINISH://eop
            next_state  = IDLE;
        default:
            begin
                next_state = IDLE;
            end                    
    endcase
end                       

//写次数                
always @ (posedge clk or negedge rst_n)
begin
    if(~rst_n)
       wtimes <= 7'b0;
    else if(current_state == IDLE && next_state == IDLE)
       wtimes <= 7'b0; 
    else if(next_state == READY) begin
        if({frame_len[4:0]} != 5'b0) 
            wtimes <= frame_len[10:5] + 7'b1 ;
        else
            wtimes <= frame_len[10:5];
    end
    else if(wtimes > 7'b0)
       wtimes <= wtimes - 7'b1;
    else
       wtimes <= wtimes;
end                       
                       
always @ (posedge clk or negedge rst_n)
begin
    if(~rst_n)
        dpram0_addr <= 6'd0;
    else if(current_state == IDLE)
        dpram0_addr <= 6'd0;        
    else if(wtimes > 7'b1)
        dpram0_addr <= dpram0_addr + 6'd1;
    else 
        dpram0_addr <= dpram0_addr;
end


always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_data_dsav    <= 1'b0;
    else if (current_state == READY)
        insert_data_dsav    <= 1'b1;
    else if (current_state == FINISH) 
        insert_data_dsav    <= 1'b0;
    else 
        insert_data_dsav    <= insert_data_dsav;
        
end

always @ (posedge clk or negedge rst_n)
begin
    if(~rst_n)
    begin
        insert_data_val_o <= 1'b0;
        insert_data_o     <= 256'b0;
    end
    else if((current_state == START) || (current_state == TRANS) || (current_state == FINISH))
    begin
        insert_data_val_o <= 1'b1;
        insert_data_o     <= dpram0_data;
    end
    else
    begin
        insert_data_val_o <= 1'b0;
        insert_data_o     <= 256'b0;
    end
end             

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_data_sop     <= 1'b0;
    else if (current_state == START)
        insert_data_sop     <= 1'b1;
    else
        insert_data_sop     <= 1'b0;
end

always @ (posedge clk or negedge rst_n)
begin
    if (~rst_n)
        insert_data_mode    <= 5'b0;
    else if (current_state == FINISH)
        insert_data_mode    <= frame_len[4:0];
    else
        insert_data_mode    <= 5'b0;
end
                      
always @ (posedge clk or negedge rst_n)
begin
    if(~rst_n)
    begin
        insert_data_eop <= 1'b0;    
        trans_end       <= 1'b0;
    end
    else if (current_state == FINISH)
    begin
        insert_data_eop <=  1'b1;    
        trans_end       <= 1'b1;
    end
    else
    begin
        insert_data_eop <=  1'b0;
        trans_end       <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        trans_end_ff1   <= 1'b0;
    end
    else begin
        trans_end_ff1   <= trans_end;
    end
end

endmodule                                    
